TabView
Scripting 提供了与最新 iOS TabView 体系一致的 API:
通过 TabView、Tab、TabSection 组织界面结构,使应用能够在 iOS 18+ 环境下完整支持多标签视图、侧边栏标签、可定制布局等。
相比旧版本依赖 tabItem 修饰符的方式,新的结构更加灵活、分组更清晰,并能与 TabViewCustomization 等新特性无缝配合。
一、基础结构:TabView + Tab
在最基本的形式中,TabView 作为容器,内部包含多个 Tab。
每个 Tab 定义:
- 标签标题
- 图标
- 标识值(value)
- 角色(如 search)
- 对应的内容视图
示例:
1function RootView() {
2 const selection = useObservable<number>(0)
3
4 return (
5 <TabView selection={selection}>
6 <Tab
7 title="首页"
8 systemImage="house.fill"
9 value={0}
10 >
11 <HomeView />
12 </Tab>
13
14 <Tab
15 title="搜索"
16 systemImage="magnifyingglass"
17 value={1}
18 role="search"
19 >
20 <SearchView />
21 </Tab>
22
23 <Tab
24 title="设置"
25 systemImage="gearshape.fill"
26 value={2}
27 >
28 <SettingsView />
29 </Tab>
30 </TabView>
31 )
32}
要点:
selection 通过 Observable 控制当前激活的标签
value 必须与 selection 的泛型类型匹配(string 或 number)
- Search Tab 可使用
role="search" 与搜索相关行为联动
二、使用 TabSection 组织分组标签
当 Tab 数量较多、需要按功能分类、需要在侧边栏中显示复杂结构时,可以使用 TabSection。
结构关系为:
TabView
├─ TabSection
│ ├─ Tab
│ ├─ Tab
│ └─ ...
├─ TabSection
│ ├─ Tab
│ └─ ...
1. 使用 title 作为分组标题
1<TabView selection={selection}>
2 <TabSection title="收件箱">
3 <Tab title="收件箱" systemImage="tray.fill" value="inbox">
4 <InboxView />
5 </Tab>
6 <Tab title="已发送" systemImage="paperplane.fill" value="sent">
7 <SentView />
8 </Tab>
9 </TabSection>
10
11 <TabSection title="标签">
12 <Tab title="重要" systemImage="star.fill" value="important">
13 <ImportantView />
14 </Tab>
15 </TabSection>
16</TabView>
如需显示图标、说明文字或复合内容,可用 header:
1<TabSection
2 header={
3 <HStack spacing={8}>
4 <Image systemName="folder.fill" />
5 <VStack>
6 <Text fontWeight="bold">项目</Text>
7 <Text fontSize={12} foregroundColor="secondary">
8 最近打开的项目
9 </Text>
10 </VStack>
11 </HStack>
12 }
13>
14 <Tab title="项目 A" systemImage="doc.fill" value="projectA">
15 <ProjectAView />
16 </Tab>
17</TabSection>
三、TabSection 的高级能力:布局、操作区、拖拽与可见性
TabSection 提供了丰富的分组级配置,让 Tab 分组的呈现方式更加灵活。
1. tabPlacement(标签位置策略)
支持:
automatic
pinned
sidebarOnly
例如将某组仅显示在侧边栏:
1<TabSection title="标签" tabPlacement="sidebarOnly">
2 <Tab title="重要" systemImage="star.fill" value="important">
3 <ImportantView />
4 </Tab>
5</TabSection>
2. sectionActions(分组操作区)
为某一组提供额外操作按钮:
1<TabSection
2 title="列表"
3 sectionActions={
4 <Button title="添加" systemImage="plus" action={addItem} />
5 }
6>
7 ...
8</TabSection>
3. 分组可见性与可定制行为
通过:
defaultVisibility
customizationID
customizationBehavior
draggable
dropDestination
可以为每个分组提供:
- 默认显示策略
- 是否允许用户自定义排序或隐藏
- 是否可以拖动
- 外部拖拽数据的处理
例如:
1<TabSection
2 title="文件"
3 customizationID="file-section"
4 customizationBehavior="reorderable"
5 draggable="file-section"
6 dropDestination={items => handleDrop(items)}
7>
8 ...
9</TabSection>
四、TabView 级别的高级配置
TabView 本身提供了一系列属性,可用于构建高级 UI(iOS 18~26)。
包括:
tabBarMinimizeBehavior
tabViewBottomAccessory
tabViewSearchActivation
tabViewCustomization
tabViewSidebarHeader
tabViewSidebarFooter
tabViewSidebarBottomBar
以下为每项能力的说明。
1. tabBarMinimizeBehavior(iOS 26.0+)
控制 TabBar 是否根据滚动方向自动最小化:
automatic
never
onScrollDown
onScrollUp
示例:
1<TabView
2 selection={selection}
3 tabBarMinimizeBehavior="onScrollDown"
4>
5 ...
6</TabView>
2. tabViewBottomAccessory(iOS 26.0+)
为 TabView 添加底部附加视图,例如提示栏:
1<TabView
2 selection={selection}
3 tabViewBottomAccessory={
4 <HStack>
5 <Text>左右滑动切换标签</Text>
6 <Spacer />
7 <Button title="知道了" action={dismiss} />
8 </HStack>
9 }
10>
11 ...
12</TabView>
3. tabViewSearchActivation(iOS 26.0+)
控制搜索 Tab 的激活方式:
automatic
searchTabSelection
与 role="search" 搭配使用:
1<TabView
2 selection={selection}
3 tabViewSearchActivation="searchTabSelection"
4>
5 ...
6</TabView>
4. 侧边栏附属视图(iOS 18.0+)
包括:
tabViewSidebarHeader
tabViewSidebarFooter
tabViewSidebarBottomBar
示例:
1<TabView
2 selection={selection}
3 tabViewSidebarHeader={<UserHeader />}
4 tabViewSidebarFooter={<SettingsButton />}
5 tabViewSidebarBottomBar={<UpgradeButton />}
6>
7 ...
8</TabView>
五、TabViewCustomization:标签页可定制化体系(重点补充)
TabViewCustomization 是一个可序列化的状态对象,用于存储和恢复用户对 Tab 布局的自定义行为,包括:
- Tab 分组顺序
- 分组内部的 Tab 排序
- Tab 可见性(在 TabBar 与 Sidebar 中分别独立管理)
- 重置各种设置
- 持久化与恢复
它通常放在 TabView 根视图中,通过:
1tabViewCustomization={customizationState}
来注入。
1. 创建与加载 TabViewCustomization
创建方式通常是:
1const customization = useObservable<TabViewCustomization >(() => {
2 const data = Storage.get('tab_customization')
3 if (data) {
4 return TabViewCustomization.fromData(data) ?? new TabViewCustomization()
5 }
6 return new TabViewCustomization()
7})
8
9useEffect(() => {
10 const listener = (newValue: TabViewCustomization) => {
11 const data = newValue.toData()
12 if (data) {
13 Storage.set('tab_customization', data)
14 }
15 }
16 customization.subscribe(listener)
17 return () => {
18 customization.unsubscribe(listener)
19 }
20}, [])
如需创建一个新的空自定义对象,可使用:
1const customizationState = useObservable(() => new TabViewCustomization())
2. 保存自定义内容
你可以将用户调整后的 Tab 布局序列化保存:
1const data = customization.value?.toData()
2Storage.set('tab_customization', data)
toData() 会将内部状态转换为可存储的 Data 对象。
3. 获取并操作分组(Section)
1getSection(id: string): TabViewCustomizationSection | null
TabSection 通常带有 customizationID,这样就可以获取特定分组并操作它:
1const section = customization.value?.getSection('file-section')
2
3section?.tabOrder // 一个包含 tab ID 顺序的数组,或 null
4section?.resetTabOrder() // 重置排序
场景示例:
- 用户将“文件”分组中的 Tab 重新排序
- 用户将某些 Tab 移动到“更多”区域
- 应用需要根据用户排序更新 UI
4. 获取并操作单个 Tab
1getTab(id: string): TabViewCustomizationTab | null
可通过 Tab 的 customizationID 获取并调整其可见性:
1const tab = customization.value?.getTab('important-tab')
2
3tab?.tabBarVisibility // Visibility 类型
4tab.sidebarVisibility = 'hidden'
适用场景:
- 控制 Tab 在 TabBar 或 Sidebar 中是否显示
- 用户可通过自定义界面操作 Tab 可见性
- 程序自动隐藏某些 Tab
5. 全局重置
1resetSectionOrder(): void
2resetVisibility(): void
通常用于:
- 点击“恢复默认布局”按钮
- 版本更新后清理已有布局逻辑
示例:
1<Button
2 title="恢复默认"
3 action={() => {
4 customization.value?.resetSectionOrder()
5 customization.value?.resetVisibility()
6 }}
7/>
六、与旧的 tabItem 写法的关系
此文档采用全新的结构化写法:
- TabView
- Tab
- TabSection
- TabViewCustomization
旧的 tabItem 写法仍可用于简单场景以及兼容iOS 17,但与侧边栏、Tab 分组、自定义布局等高级能力不兼容。
在复杂应用中,建议全面迁移到新的组件体系。